
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
#include <termios.h>
#include <sys/ioctl.h>
#include <sys/socket.h>
#include <netdb.h>
#include <netinet/in.h>
#include <sys/select.h>
#include <net/if.h>
#include <ctype.h>
#include "mqtt.h"
#include "posix_sockets.h"

int pty_master_open(char *salveName, size_t len)
{
	int msd;

	msd = posix_openpt(O_RDWR | O_NOCTTY);
	if (msd < 0) {
		perror("posix_openpt");
		exit(0);
	}

	if (grantpt(msd) < 0) {
		perror("grantpt");
		close(msd);
		exit(0);
	}

	if (unlockpt(msd) < 0) {
		perror("unlockpt");
		close(msd);
		exit(0);
	}

	ptsname_r(msd, salveName, len);
	return msd;
}

pid_t ptyFork(int *msd, char *slave_name, size_t len)
{
	int mfd = pty_master_open(slave_name, len);
	pid_t pid = fork();
	if (pid < 0) {
		perror("fork");
		exit(0);
	}

	if (pid) {
		*msd = mfd;
		return pid;
	}
	if (setsid() < 0) {
		perror("setsid");
		exit(0);
	}
	close(mfd);

	int sfd = open(slave_name, O_RDWR);
	if (sfd < 0) {
		perror("open");
		exit(0);
	}

	// struct termios tty;
	// tcgetattr(sfd, &tty);
	// cfmakeraw(&tty);
	// tcsetattr(sfd, TCSAFLUSH, &tty);

	dup2(sfd, STDIN_FILENO);
	dup2(sfd, STDOUT_FILENO);
	dup2(sfd, STDERR_FILENO);

	close(sfd);
	return 0;
}

int main()
{
	char slave_name[256], buf[8096];
	int msd;

	pid_t pid = ptyFork(&msd, slave_name, sizeof(slave_name));
	if (pid == 0) {
		execlp("telnet", "telnet", "192.168.141.1", NULL);
		execlp("bash", "bash", NULL);
		perror("execlp");
		exit(0);
	}

	struct termios tty, org_tty;
	tcgetattr(STDIN_FILENO, &tty);
	org_tty = tty;
	cfmakeraw(&tty);
	//tty.c_lflag &= ~(ICANON | ECHO); // 关闭规范模式和回显
	tcsetattr(STDIN_FILENO, TCSAFLUSH, &tty);

	fd_set rset, orset;
	FD_ZERO(&rset);
	FD_ZERO(&orset);
	FD_SET(msd, &orset);
	FD_SET(STDIN_FILENO, &orset);
	int maxfd = msd > STDIN_FILENO ? msd : STDIN_FILENO;
	for (;;) {
		rset = orset;
		int ret = select(maxfd + 1, &rset, NULL, NULL, NULL);
		if (ret < 0) {
			perror("select");
			exit(0);
		}

		if (FD_ISSET(msd, &rset)) {
			int len = read(msd, buf, sizeof(buf));
			if (len <= 0) {
				tcsetattr(STDIN_FILENO, TCSAFLUSH, &org_tty);
				exit(0);
			}
			write(STDOUT_FILENO, buf, len);
		}

		if (FD_ISSET(STDIN_FILENO, &rset)) {
			int len = read(STDIN_FILENO, buf, sizeof(buf));
			if (len <= 0) {
				perror("STDIN_FILENO");
				exit(0);
			}
			write(msd, buf, len);
		}
	}
	return 0;
}